package communication

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"crypto/sha256"
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/http"
	"time"
)

var (
	// 默认共享密钥，应在初始化时设置
	sharedSecret = "default_shared_secret"

	// 默认超时时间
	defaultTimeout = 10 * time.Second

	// HTTP客户端
	httpClient = &http.Client{
		Timeout: defaultTimeout,
	}
)

// SetSharedSecret 设置组件间通信的共享密钥
func SetSharedSecret(secret string) {
	if secret != "" {
		sharedSecret = secret
	}
}

// SetTimeout 设置HTTP请求超时时间
func SetTimeout(timeout time.Duration) {
	if timeout > 0 {
		defaultTimeout = timeout
		httpClient.Timeout = timeout
	}
}

// Request 组件间通信请求
type Request struct {
	Target  string      `json:"-"`         // 目标组件地址
	Path    string      `json:"-"`         // API路径
	Method  string      `json:"-"`         // HTTP方法
	Headers http.Header `json:"-"`         // HTTP头
	Payload interface{} `json:"payload"`   // 请求负载
	Time    int64       `json:"timestamp"` // 时间戳
}

// Response 组件间通信响应
type Response struct {
	Success bool        `json:"success"` // 是否成功
	Message string      `json:"message"` // 消息
	Data    interface{} `json:"data"`    // 响应数据
}

// NewRequest 创建新的组件间通信请求
func NewRequest(target, path, method string, payload interface{}) *Request {
	return &Request{
		Target:  target,
		Path:    path,
		Method:  method,
		Headers: make(http.Header),
		Payload: payload,
		Time:    time.Now().Unix(),
	}
}

// Send 发送组件间通信请求
func (r *Request) Send() (*Response, error) {
	// 验证必要字段
	if r.Target == "" {
		return nil, errors.New("目标组件地址不能为空")
	}

	// 构建完整URL
	url := fmt.Sprintf("%s%s", r.Target, r.Path)

	// 序列化请求
	reqData, err := json.Marshal(r)
	if err != nil {
		return nil, fmt.Errorf("序列化请求失败: %w", err)
	}

	// 加密请求体
	encryptedData, err := encrypt(reqData, sharedSecret)
	if err != nil {
		return nil, fmt.Errorf("加密请求失败: %w", err)
	}

	// 创建HTTP请求
	req, err := http.NewRequest(r.Method, url, bytes.NewBuffer([]byte(encryptedData)))
	if err != nil {
		return nil, fmt.Errorf("创建HTTP请求失败: %w", err)
	}

	// 设置请求头
	req.Header.Set("Content-Type", "application/x-component-comms")
	req.Header.Set("X-Component-Timestamp", fmt.Sprintf("%d", r.Time))

	// 添加自定义请求头
	for k, v := range r.Headers {
		for _, val := range v {
			req.Header.Add(k, val)
		}
	}

	// 发送请求
	resp, err := httpClient.Do(req)
	if err != nil {
		return nil, fmt.Errorf("发送请求失败: %w", err)
	}
	defer resp.Body.Close()

	// 读取响应
	respBody, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("读取响应失败: %w", err)
	}

	// 如果响应状态码不是2xx，返回错误
	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
		return &Response{
			Success: false,
			Message: fmt.Sprintf("请求失败，状态码: %d", resp.StatusCode),
			Data:    string(respBody),
		}, nil
	}

	// 尝试解密响应
	decryptedData, err := decrypt(string(respBody), sharedSecret)
	if err != nil {
		// 如果解密失败，尝试直接解析
		var response Response
		if jsonErr := json.Unmarshal(respBody, &response); jsonErr != nil {
			return nil, fmt.Errorf("解析响应失败: %w", jsonErr)
		}
		return &response, nil
	}

	// 解析解密后的响应
	var response Response
	if err := json.Unmarshal(decryptedData, &response); err != nil {
		return nil, fmt.Errorf("解析解密响应失败: %w", err)
	}

	return &response, nil
}

// VerifyRequest 验证组件间通信请求
func VerifyRequest(r *http.Request) ([]byte, error) {
	// 检查必要请求头
	timestamp := r.Header.Get("X-Component-Timestamp")
	if timestamp == "" {
		return nil, errors.New("缺少时间戳")
	}

	// 检查请求类型
	contentType := r.Header.Get("Content-Type")
	if contentType != "application/x-component-comms" {
		return nil, errors.New("不支持的内容类型")
	}

	// 读取请求体
	encryptedData, err := io.ReadAll(r.Body)
	if err != nil {
		return nil, fmt.Errorf("读取请求体失败: %w", err)
	}

	// 关闭并替换请求体（允许后续处理读取）
	r.Body.Close()
	r.Body = io.NopCloser(bytes.NewBuffer(encryptedData))

	// 解密请求体
	return decrypt(string(encryptedData), sharedSecret)
}

// HandleComponentRequest 处理组件间通信请求的HTTP处理器
func HandleComponentRequest(handler func(payload []byte) (*Response, error)) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		// 验证和解密请求
		payload, err := VerifyRequest(r)
		if err != nil {
			http.Error(w, fmt.Sprintf("无效的组件请求: %v", err), http.StatusBadRequest)
			return
		}

		// 处理请求
		response, err := handler(payload)
		if err != nil {
			// 出错时返回错误响应
			response = &Response{
				Success: false,
				Message: err.Error(),
			}
		}

		// 如果没有返回响应，创建一个默认的成功响应
		if response == nil {
			response = &Response{
				Success: true,
				Message: "处理成功",
			}
		}

		// 序列化响应
		respData, err := json.Marshal(response)
		if err != nil {
			http.Error(w, fmt.Sprintf("序列化响应失败: %v", err), http.StatusInternalServerError)
			return
		}

		// 加密响应
		encryptedResp, err := encrypt(respData, sharedSecret)
		if err != nil {
			http.Error(w, fmt.Sprintf("加密响应失败: %v", err), http.StatusInternalServerError)
			return
		}

		// 发送响应
		w.Header().Set("Content-Type", "application/x-component-comms")
		w.Write([]byte(encryptedResp))
	}
}

// 对数据进行加密
func encrypt(data []byte, secret string) (string, error) {
	key := deriveKey(secret)

	// 创建一个新的AES密码块
	block, err := aes.NewCipher(key)
	if err != nil {
		return "", err
	}

	// 创建一个新的GCM模式
	aesGCM, err := cipher.NewGCM(block)
	if err != nil {
		return "", err
	}

	// 创建随机nonce
	nonce := make([]byte, aesGCM.NonceSize())
	if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
		return "", err
	}

	// 加密数据
	ciphertext := aesGCM.Seal(nonce, nonce, data, nil)

	// 编码为base64字符串
	return base64.StdEncoding.EncodeToString(ciphertext), nil
}

// 对加密数据进行解密
func decrypt(encryptedData string, secret string) ([]byte, error) {
	key := deriveKey(secret)

	// 解码base64字符串
	ciphertext, err := base64.StdEncoding.DecodeString(encryptedData)
	if err != nil {
		return nil, err
	}

	// 创建一个新的AES密码块
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}

	// 创建一个新的GCM模式
	aesGCM, err := cipher.NewGCM(block)
	if err != nil {
		return nil, err
	}

	// 获取nonce大小
	nonceSize := aesGCM.NonceSize()
	if len(ciphertext) < nonceSize {
		return nil, errors.New("密文太短")
	}

	// 提取nonce和实际的密文
	nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:]

	// 解密数据
	return aesGCM.Open(nil, nonce, ciphertext, nil)
}

// 从密钥文本导出固定长度密钥
func deriveKey(secret string) []byte {
	// 使用SHA256生成固定长度密钥
	hash := sha256.Sum256([]byte(secret))
	return hash[:]
}
